package core.bmp.utils;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.imageio.ImageIO;

import core.bmp.model.BmpData;

/**
 * 用于读取Bmp图像的工具类。
 * 
 * @author 陈锡强
 * @since 2015年11月23日08:35:34
 */
public class BmpUtils {

	/* 图像读写 */

	private static final int LEN_FILE_HEADER = 14;
	private static final int LEN_INFO_HEADER = 40;

	public static BmpData loadBmp(String bmpFilePath) throws IOException {
		return loadBmp(new File(bmpFilePath));
	}

	public static BmpData loadBmp(File bmpFile) throws IOException {
		FileInputStream in = null;
		try {
			in = new FileInputStream(bmpFile);

			// 读入文件头和信息头
			byte header[] = new byte[LEN_FILE_HEADER];
			byte info[] = new byte[LEN_INFO_HEADER];
			in.read(header, 0, LEN_FILE_HEADER);
			in.read(info, 0, LEN_INFO_HEADER);

			// 宽高、色彩位数、尺寸
			int biWidth = IntegerUtil.bytesToInt(info, 4, 4);
			int biHeight = IntegerUtil.bytesToInt(info, 8, 4);
			int biCount = IntegerUtil.bytesToInt(info, 14, 2);
			int biSizeImage = IntegerUtil.bytesToInt(info, 20, 4);

			// 这里只处理24位真彩色图像
			if (biCount != 24) {
				throw new IllegalStateException("只能处理24位真彩色图像");
			}

			// 计算补位
			int npad = (biSizeImage / biHeight) - biWidth * 3;
			if (npad == 4) {// 当每行为4的倍数时无需补位
				npad = 0;
			}

			// 读入数据，每一行都为4的倍数
			int size = (biWidth + npad) * 3 * biHeight;
			byte alRgb[];
			if (npad != 0) {
				alRgb = new byte[(biWidth + npad) * 3 * biHeight];
			} else {
				alRgb = new byte[biSizeImage];
			}
			in.read(alRgb, 0, size);

			// 从数据中提取像素，使用4个字节的int去携带3个字节的像素值
			int rgbData[] = new int[biHeight * biWidth];
			int idx = 0;
			int pix;
			for (int j = 0; j < biHeight; j++) {
				for (int i = 0; i < biWidth; i++) {
					pix = IntegerUtil.bytesToInt(alRgb, idx, 3);// RGB像素值
					pix = pix | (255 & 0xFF) << 24;// 补上一位A，组成ARGB
					rgbData[biWidth * (biHeight - j - 1) + i] = pix;
					idx += 3;
				}
				idx += npad;
			}

			return new BmpData(biWidth, biHeight, biCount, rgbData);
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static void saveBmp(BmpData bmpData, File bmpFile) throws IOException {
		BufferedImage img = new BufferedImage(bmpData.getWidth(), bmpData.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
		img.getGraphics().drawImage(bmpDataToImage(bmpData), 0, 0, null);
		ImageIO.write(img, "bmp", bmpFile);
	}

	public static void saveBmp(BufferedImage buffImg, File bmpFile) throws IOException {
		ImageIO.write(buffImg, "bmp", bmpFile);
	}

	/* 数据转换 */

	public static Image bmpDataToImage(BmpData bmpData) {
		return Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(bmpData.getWidth(), bmpData.getHeight(),
				bmpData.getArgbPix(), 0, bmpData.getWidth()));
	}
}
